package org.carabiner.infopanel;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;

import org.carabiner.util.CarabinerException;
import org.carabiner.util.CarabinerProperties;

/**
 * A tree model to display the components of a Carabiner test subject with nodes
 * for any warnings associatied with given sub-components.
 * 
 * <p>
 * Carabiner Testing Framework
 * </p>
 * <p>
 * Copyright: <a href="http://www.gnu.org/licenses/gpl.html">GNU Public License</a>
 * </p>
 * 
 * @author John Januskey (john.januskey@gmail.com)
 * 
 */
class CarabinerMessageTreeModel extends DefaultTreeModel
{
  private Map m_ComponentToWarningListMap;

  private Icon m_ComponentIcon;

  private Color m_ComponentHighlightColor;

  public CarabinerMessageTreeModel(Component rootComponent, List warnings)
  {
    this(rootComponent, warnings, new ImageIcon(new CarabinerException("")
        .getClass().getResource("control.gif")), CarabinerProperties
        .getDefaultComponentHighlightColor());
  }

  public CarabinerMessageTreeModel(Component rootComponent, List warnings,
      Icon componentIcon, Color componentHighlightColor)
  {
    super(null);

    m_ComponentToWarningListMap = processWarnings(warnings);
    m_ComponentIcon = componentIcon;
    m_ComponentHighlightColor = componentHighlightColor;

    TreeNode root = getNode(rootComponent, m_ComponentToWarningListMap);
    super.setRoot(root);
  }

  /**
   * Creates a treenode for the specified component. If the component is a
   * container, a node will be added to the returned node for each component
   * contained in the container component.
   * 
   * @param component
   *          Component
   * @return DefaultMutableTreeNode
   */
  private DefaultMutableTreeNode getNode(Component component,
      Map componentToWarningListMap)
  {
    DefaultMutableTreeNode node = new CarabinerComponentNode(component,
        m_ComponentIcon, m_ComponentHighlightColor);

    if (componentToWarningListMap.containsKey(component))
    {
      ArrayList warnings = (ArrayList) componentToWarningListMap.get(component);
      for (int i = 0; i < warnings.size(); i++)
      {
        CarabinerMessage message = (CarabinerMessage) warnings.get(i);
        CarabinerMessageNode warningNode = new CarabinerMessageNode(message);

        node.add(warningNode);
      }
    }
    if (component instanceof Container)
    {
      Component[] children = ((Container) component).getComponents();
      for (int i = 0; i < children.length; i++)
      {
        node.add(getNode(children[i], componentToWarningListMap));
      }
    }

    return node;
  }

  /**
   * Creates a map that contains a list of warnings for each component contained
   * in the specified warning list.
   * 
   * @param warnings
   *          List
   * @return Map
   */
  private Map processWarnings(List warnings)
  {
    Hashtable warningMap = new Hashtable();
    for (int i = 0; i < warnings.size(); i++)
    {
      CarabinerMessage message = (CarabinerMessage) warnings.get(i);
      Component comp = message.getComponent();
      if (!warningMap.containsKey(comp))
      {
        warningMap.put(comp, new ArrayList());
      }

      ((List) warningMap.get(comp)).add(message);
    }
    return warningMap;
  }

  /**
   * getComponentToWarningMap
   * 
   * @return Map
   */
  Map getComponentToWarningMap()
  {
    return m_ComponentToWarningListMap;
  }
}
